package study.exception;


import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import study.ApiResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

@ControllerAdvice
public class GlobalExceptionHandler {
    Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(Exception exception, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws Exception {
        //获取拦截器判断的返回结果类型
        Object o = httpRequest.getAttribute(SysConsts.IS_METHOD_RETURN_VIEW);
        //默认返回Json
        if (o == null) {
            o = false;
        }
        //是否是html/text
        boolean isView = (Boolean) o;

        ApiResponse response = new ApiResponse();
        StringBuffer msg =new StringBuffer();
        response.setCode(ErrorDefine.UNKNOWN_ERROR.code);
        if(exception instanceof MethodArgumentNotValidException){
            MethodArgumentNotValidException validException = (MethodArgumentNotValidException)exception;
            BindingResult result=validException.getBindingResult();
            List<ObjectError> errors=result.getAllErrors();
            for(ObjectError error:errors){
                msg.append(error.getObjectName());
                msg.append(":\t");
                msg.append(error.getDefaultMessage());
                msg.append("\n");
            }
            response.setMessage(msg.toString());
            log.error(msg.toString(),exception);
        }else if(exception instanceof BusinessException || exception.getCause() instanceof BusinessException){//2017-06-21 新增对系统业务异常的处理(去掉BusinessException:开头)
            BusinessException businessException = (BusinessException)(exception.getCause());
            if(businessException != null){
                msg.append(businessException.getMessage());
            }else{
                msg.append(exception.getMessage());
            }
            response.setCode(businessException.getErrorCode());
            log.info("【业务异常】-"+msg.toString());
        }else if(exception instanceof ClientAbortException){
            msg.append("系统异常："+ ExceptionUtils.getRootCauseMessage(exception));
            if(exception.getMessage() != null && exception.getMessage().indexOf("断开的管道") >-1){
                log.error("【系统异常】-"+exception.getMessage());
            }else{
                log.error("【系统异常】-"+exception.getMessage(),exception);
            }
        }else{
            //Sentinel的异常：可能有更好的处理方式，
            // 可以参照https://www.bilibili.com/read/cv5030244/统一制定规范。
            String sentinalMsg = null;
            String message = exception.getMessage();
            if(message != null){
                if(message.indexOf("FlowException") > -1){
                    sentinalMsg = "限流了";
                }
                if(message.indexOf("DegradeException") > -1){
                    sentinalMsg = "降级了";
                }
                if(message.indexOf("ParamFlowException") > -1){
                    sentinalMsg = "热点参数限流";
                }
                if(message.indexOf("SystemBlockException") > -1){
                    sentinalMsg = "系统规则（负载/...不满足要求）";
                }
                if(message.indexOf("AuthorityException") > -1){
                    sentinalMsg = "授权规则不通过";
                }
            }
            String tipMessage = "";
            if(sentinalMsg != null){
                log.error("【系统异常】-"+sentinalMsg);
                tipMessage = "系统异常："+sentinalMsg;
            }else{
                log.error("【系统异常】-"+message,exception);
                tipMessage = "系统出现未知异常："+message;
            }
            msg.append(tipMessage);

        }
        response.setMessage(msg.toString());
        if(isView){
            ModelAndView modelAndView = new ModelAndView("/error");//配置需要跳转的Controller方法
            httpRequest.setAttribute("message", response.getMessage());
            return modelAndView;
        }else{
            ModelAndView  modelAndView = new ModelAndView(new MappingJackson2JsonView());
            modelAndView.addObject("code", response.getCode());
            modelAndView.addObject("message", response.getMessage());
            modelAndView.addObject("data", null);
            return modelAndView;
        }
    }
}
